//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"
#include "algobase.h"
#include "utility.h"

FC_NAMESPACE_BEGIN


// minmax.h (minimum/maximum operations)
//
// clamp					(algobase.h)
// min
// max
// min_element
// max_element
// minmax
// minmax_element
// median
// lexicographical_compare	(algobase.h)



// min

template <class T, class Compare>
const T& min( const T& a, const T& b, Compare compare )
	{
		return compare(a, b) ? a : b;
	}


// max

template <class T, class Compare>
const T& max( const T& a, const T& b, Compare compare )
	{
		return compare(a, b) ? b : a;
	}


// min_element

template <class ForwardIterator, class Compare> inline
	ForwardIterator min_element( ForwardIterator first, ForwardIterator last, Compare compare )
	{
		ForwardIterator minElement = first;
		if( FC_LIKELY(first != last) )
		{
			while( ++first != last )
			{
				if( compare(*first, *minElement) )
					minElement = first;
			}
		}

		return minElement;
	}

template <class ForwardIterator> inline
	ForwardIterator min_element( ForwardIterator first, ForwardIterator last )
	{
		return min_element(first, last,
			less<typename iterator_traits<ForwardIterator>::value_type>());
	}


// max_element

template <class ForwardIterator, class Compare> inline
	ForwardIterator max_element( ForwardIterator first, ForwardIterator last, Compare compare )
	{
		ForwardIterator maxElement = first;
		if( FC_LIKELY(first != last) )
		{
			while( ++first != last )
			{
				if( compare(*maxElement, *first) )
					maxElement = first;
			}
		}

		return maxElement;
	}

template <class ForwardIterator> inline
	ForwardIterator max_element( ForwardIterator first, ForwardIterator last )
	{
		return max_element( first, last,
			less<typename iterator_traits<ForwardIterator>::value_type>() );
	}


// minmax

template <class T> inline
	pair<const T&, const T&> minmax( const T& a, const T& b )
	{
		return a < b ? pair<const T&, const T&>(a, b) : pair<const T&, const T&>(b, a);
	}

template <class T, class Compare> inline
	pair<const T&, const T&> minmax( const T& a, const T& b, Compare compare )
	{
		return compare(a, b) ? pair<const T&, const T&>(a, b) : pair<const T&, const T&>(b, a);
	}


// minmax_element

template <class ForwardIterator, class Compare> inline
	pair<ForwardIterator, ForwardIterator> minmax_element( ForwardIterator first, ForwardIterator last, Compare compare )
	{
		ForwardIterator minElement = first;
		ForwardIterator maxElement = first;
		if( FC_LIKELY(first != last) )
		{
			while( ++first != last )
			{
				if( compare(*first, *minElement) )
					minElement = first;
				else if( compare(*maxElement, *first) )
					maxElement = first;
			}
		}

		return pair<ForwardIterator, ForwardIterator>(minElement, maxElement);
	}

template <class ForwardIterator> inline
	pair<ForwardIterator, ForwardIterator> minmax_element( ForwardIterator first, ForwardIterator last )
	{
		return minmax_element( first, last,
			less<typename iterator_traits<ForwardIterator>::value_type>() );
	}


// median

template <class T, class Compare> inline
	const T& median( const T& a, const T& b, const T& c, Compare compare )
	{
		return compare(a, b) ?
			( compare(b, c) ? b : ( compare(a, c) ? c : a ) ) :
			( compare(a, c) ? a : ( compare(b, c) ? c : b ) );
	}

template <class T> inline
	const T& median( const T& a, const T& b, const T& c )
	{
		return (a < b) ?
			( (b < c) ? b : ( (a < c) ? c : a ) ) :
			( (a < c) ? a : ( (b < c) ? c : b ) );
	}




FC_NAMESPACE_END
